using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace PeDALS.Tools.AZ.PSTArchive.PSTData
{
    public class PropertyValue
    {
        private UInt16 m16Tag;
        private UInt16 m16Type;
        private object moValue;
        private string mstrXMLValue;
        private bool mblnInvalidChars;

        public PropertyValue(UInt16 u16Tag, UInt16 u16Type, object oValue)
        {
            m16Tag = u16Tag;
            m16Type = u16Type;
            moValue = oValue;
        }

        public String Name
        {
            get
            {
                if (DynProps.Props.ContainsKey(Tag))
                {
                    return DynProps.Props[Tag].DisplayName;
                }
                else
                {
                    return string.Format("x{0:x8}", Tag);
                }
            }
        }

        public UInt32 Tag
        {
            get { return Convert.ToUInt32(m16Tag) << 16 | Convert.ToUInt32(m16Type); }
        }

        public object Value
        {
            get { return moValue; }
        }

        public string struValue
        {
            get
            {
                System.Text.UnicodeEncoding ueEncoder = new System.Text.UnicodeEncoding();
                return ueEncoder.GetString((byte[])moValue);
            }
        }

        public string straValue
        {
            get
            {
                System.Text.UTF8Encoding aeEncoder = new System.Text.UTF8Encoding();
                return aeEncoder.GetString((byte[])moValue);
            }
        }

        public string XMLValue
        {
            get { return mstrXMLValue;}
        }

        public bool InvalidChars
        {
            get
            {
                StringBuilder sbOutput = new StringBuilder();
                if (Convert.ToBoolean(m16Type & 0x1000))
                {
                    if (moValue.GetType().IsGenericType)
                    {
                        if (moValue.GetType().GetGenericTypeDefinition().Equals(typeof(List<>)))
                        {
                            XmlWriterSettings xwsOutput = new XmlWriterSettings();
                            xwsOutput.ConformanceLevel = ConformanceLevel.Fragment;
                            xwsOutput.OmitXmlDeclaration = true;
                            XmlWriter xwOutput = XmlWriter.Create(sbOutput, xwsOutput);
                            foreach (object oValue in (List<object>)moValue)
                            {
                                string strOutput = "";
                                xwOutput.WriteStartElement("MultiValue");
                                try
                                {
                                    strOutput = WriteValue(Convert.ToUInt16(m16Type & 0xFFF), moValue);
                                    if (mblnInvalidChars)
                                    {
                                        xwOutput.WriteRaw(strOutput);
                                    }
                                    else
                                    {
                                        xwOutput.WriteString(strOutput);
                                    }
                                }
                                catch
                                {
                                    if (mblnInvalidChars)
                                    {
                                        xwOutput.WriteRaw(strOutput);
                                    }
                                    else
                                    {
                                        xwOutput.WriteString(strOutput);
                                    }
                                }
                                xwOutput.WriteEndElement();
                            }
                            xwOutput.Flush();
                            xwOutput.Close();
                            xwOutput = null;
                            xwOutput = null;
                        }
                    }
                }
                else
                {
                    sbOutput.Append(WriteValue(Convert.ToUInt16(m16Type & 0xFFF), moValue));
                }
                mstrXMLValue = sbOutput.ToString();

                return mblnInvalidChars;
            }
        }

        private string WriteValue(UInt16 u16Type, object oValue)
        {
            string strReturn = "";
            switch (u16Type)
            {
                case 0xD:
                case 0x102:
                    byte[] baValue = (byte[])oValue;
                    long lngTotalBytes = baValue.LongLength;
                    if (lngTotalBytes > 0)
                    {
                        long lngPrintable = 0;
                        long lngZero = 0;
                        long lngWindow = 4;
                        long lngPointer = 0;
                        long lngOrigin = 0;
                        foreach (byte bChar in baValue)
                        {
                            //lngPointer++;
                            //if ((lngPointer - lngOrigin) <= lngWindow)
                            //{
                                if (bChar == 0)
                                {
                                    lngZero++;
                                }
                                else if (bChar == 0x9 /* == '\t' == 9   */       ||
                                         bChar == 0xA /* == '\n' == 10  */       ||
                                         bChar == 0xD /* == '\r' == 13  */       ||
                                        (bChar >= 0x20 && bChar <= 0x7F))
                                {
                                    lngPrintable++;
                                }
                                if ((lngPointer - lngOrigin) == lngZero)
                                {

                                }

                            //}
                        }

                        if ((((lngPrintable + lngZero) * 100) / lngTotalBytes) > 70)
                        {
                            if (lngZero > lngPrintable)
                            {
                                System.Text.UnicodeEncoding ueEncoder = new System.Text.UnicodeEncoding();
                                strReturn = EvaluateString(ueEncoder.GetString((byte[])oValue));
                            }
                            else
                            {
                                System.Text.UTF8Encoding aeEncoder = new System.Text.UTF8Encoding();
                                strReturn = EvaluateString(aeEncoder.GetString((byte[])oValue));
                            }
                        }
                    }
                    strReturn = strReturn.Length > 0 ? strReturn : oValue.GetType() != typeof(string) ? Convert.ToBase64String((byte[])oValue) : (string)oValue;

                        //switch (m16Tag)
                        //{
                        //    case 0x0038:
                        //    case 0x003b:
                        //    case 0x003f:
                        //    case 0x0041:
                        //    case 0x0043:
                        //    case 0x0045:
                        //    case 0x0046:
                        //    case 0x0047:
                        //    case 0x004c:
                        //    case 0x004f:
                        //    case 0x0051:
                        //    case 0x0052:
                        //    case 0x0053:
                        //    case 0x0054:
                        //    case 0x0056:
                        //    case 0x005b:
                        //    case 0x005c:
                        //    case 0x005e:
                        //    case 0x005f:
                        //    case 0x007f:
                        //    case 0x0c19:
                        //    case 0x0c1d:
                        //    case 0x0fff:
                        //    case 0x1009:
                        //    case 0x1013:
                        //    //case 0x300b:
                        //        strReturn = EvaluateString(Encoding.Default.GetString((byte[])oValue));
                        //        break;
                        //    default:
                        //        break;
                        //}
                        break;
                case 0x1e:
                case 0x1f:
                    strReturn = EvaluateString((string)oValue);
                    break;
                default:
                    strReturn = oValue.ToString();
                    break;
            }
            return strReturn;
        }

        private string EvaluateString(object oValue)
        {
            string strReturn = "";
            StringBuilder sbOutput = new StringBuilder();
            bool blnInvalid = false;
            int intChar = 1;
            foreach (char cValue in oValue.ToString())
            {
                if (cValue == 0x9 /* == '\t' == 9   */       ||
                    cValue == 0xA /* == '\n' == 10  */       ||
                    cValue == 0xD /* == '\r' == 13  */       ||
                   (cValue >= 0x20 && cValue <= 0xD7FF)      ||
                   (cValue >= 0xE000 && cValue <= 0xFFFD)    ||
                   (cValue >= 0x10000 && cValue <= 0x10FFFF))
                {
                    if (blnInvalid)
                    {
                        sbOutput.Append(string.Format(" -->"));
                        blnInvalid = false;
                    }
                    sbOutput.Append(cValue);
                }
                else
                {
                    if (!blnInvalid)
                    {
                        sbOutput.Append(string.Format("<!-- "));
                        blnInvalid = true;
                        mblnInvalidChars = true;
                    }
                    sbOutput.Append("&#x");
                    sbOutput.Append(string.Format("{0:x4}", ((int)Convert.ToChar(cValue))));
                    sbOutput.Append(';');
                }
                intChar++;
            }
            if (blnInvalid)
            {
                sbOutput.Append(string.Format(" -->"));
            }
            strReturn = sbOutput.ToString();
            sbOutput = null;

            return strReturn;
        }
    }
}
